package com.cool.config.springsecurity;

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.cool.bo.sysmanage.stuff.UserLoginBo;
import com.cool.common.CommonResult;
import com.cool.common.ResponseCode;
import com.cool.config.springsecurity.login.UserLoginAuthenticationProvider;
import com.cool.filter.UserLoginFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.web.cors.CorsUtils;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 安全配置
 *
 * @author Jiangmanman
 * @date 2020/07/30
 */
@Configuration
@Slf4j
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private AuthenticationFailureHandler authenticationFailureHandler;
    @Resource
    private AuthenticationSuccessHandler authenticationSuccessHandler;

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //登录验证
        UserLoginFilter userLoginFilter = new UserLoginFilter();
        UserLoginAuthenticationProvider userLoginAuthenticationProvider = new UserLoginAuthenticationProvider();
        userLoginFilter.setAuthenticationManager(authenticationManagerBean());
        userLoginFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler);
        userLoginFilter.setAuthenticationFailureHandler(authenticationFailureHandler);
        //创建权限管理对象
        SecurityMetadataSource securityMetadataSource = new SecurityMetadataSource();
        AccessDecisionManager accessDecisionManager = new AccessDecisionManager();


        http
                //开启跨域访问
                .cors().and().authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll().and()
                .addFilterBefore(userLoginFilter, BasicAuthenticationFilter.class)
                .httpBasic().disable()
                //表单登录，permitAll()表示这个不需要验证 登录页面，登录失败页面
                .formLogin()
                //设置登录认证页面
                .loginPage("/system/login")
                //登录成功后的处理接口
                .loginProcessingUrl("/home")
                .failureHandler(authenticationFailureHandler)
                .successHandler(authenticationSuccessHandler)
                .and()
                .exceptionHandling()
                .accessDeniedHandler((request, response, accessDeniedException) -> {

                    response.setContentType("application/json;charset=utf-8");

                    CommonResult commonResult = CommonResult.newCommonResult().setCode(ResponseCode.PERMISSION_DENY).setMsg(accessDeniedException.getMessage());

                    response.getWriter().write(JSONUtil.toJsonStr(commonResult));

                    response.getWriter().flush();

                    response.getWriter().close();

                })
                .and()
                .authorizeRequests()
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O object) {
                        //设置当前URI拥有的权限
                        object.setSecurityMetadataSource(securityMetadataSource);
                        //判定请求是否通过
                        object.setAccessDecisionManager(accessDecisionManager);
                        return object;
                    }
                })
                .anyRequest().authenticated()
                .and()
                .csrf().disable()
                .authenticationProvider(userLoginAuthenticationProvider)
                .headers().cacheControl();
        ;
    }

    @Bean
    public PasswordEncoder createPasswordEncoder() {
        // BCryptPasswordEncoder：Spring Security 提供的加密工具，可快速实现加密加盐
        return new BCryptPasswordEncoder();
    }
}
